package bancosys.tec.persist.spring.core.context;

import jmine.tec.persist.PersistMessages;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;

/**
 * @author Frank Cara
 */
public final class BancosysSingletonApplicationContext {

    private static final String BANCOSYS_CONTEXT_NAME = "bancosys.context";

    public static final String BEAN_FACTORY = BancosysSingletonApplicationContext.class.getName() + ".BEAN_FACTORY";

    private static Log log = LogFactory.getLog(BancosysSingletonApplicationContext.class);

    private static String location = "classpath:jmine-tec-integration-test.xml";

    private final BeanFactoryLocator beanFactoryLocator;

    private BeanFactoryReference beanFactoryReference;

    /**
     * Construtor.
     */
    private BancosysSingletonApplicationContext() {
        log.debug("**************************Inicializando Application Context");
        this.beanFactoryLocator = SingletonBeanFactoryLocator.getInstance(location);

    }

    /**
     * Define a localização.
     * 
     * @param loc a localização.
     */
    public static synchronized void setLocation(String loc) {
        if (instance != null && !location.equals(loc)) {
            throw new BancosysSingletonApplicationContextException(
                    PersistMessages.SINGLETON_APPLICATION_CONTEXT_ALREADY_INITIALIZED.create(location, loc));
        }
        location = loc;
    }

    /**
     * Fecha a application context, se necessario
     */
    public synchronized void close() {
        if (this.beanFactoryReference != null) {
            this.beanFactoryReference.release();
        }
    }

    // -------------------------------------------------------
    // --------------------- singleton -----------------------

    private static volatile BancosysSingletonApplicationContext instance = null;

    /**
     * Cria a instância do contexto de aplicação do Bancosys.
     */
    private static synchronized void newInstance() {
        if (instance == null) {
            instance = new BancosysSingletonApplicationContext();
        }
    }

    /**
     * @return {@link BeanFactory}
     */
    public BeanFactory getSharedInstance() {
        System.err.println("NAO USAR ESTA CLASSE! SERA REMOVIDA NA VERSAO tec 1.5+");
        return this.getSharedBeanFactoryReference().getFactory();
    }

    /**
     * Devolve a instância do contexto de aplicação do Bancosys.
     * 
     * @return a instância do contexto de aplicação do Bancosys.
     */
    public static BancosysSingletonApplicationContext getInstance() {
        if (instance == null) {
            newInstance();
        }
        return instance;
    }

    /**
     * @return {@link BeanFactoryReference}
     */
    public BeanFactoryReference newBeanFactoryReference() {
        return this.beanFactoryLocator.useBeanFactory(BANCOSYS_CONTEXT_NAME);
    }

    /**
     * Verifica se a referencia compartilhada da beanFactory foi inicializada
     * 
     * @return boolean boolean
     */
    public synchronized boolean isSharedReferenceInitialized() {
        return this.beanFactoryReference != null;
    }

    /**
     * @return the beanFactoryReference
     * @deprecated Apenas para ser usado nos testes!!!
     */
    @Deprecated
    public synchronized BeanFactoryReference getSharedBeanFactoryReference() {
        if (this.beanFactoryReference == null) {
            this.beanFactoryReference = this.newBeanFactoryReference();
        }
        return this.beanFactoryReference;
    }
}
